#define _CRT_SECURE_NO_WARNINGS 1

#include"Tetris.h"

void Pause()
{
	SetPos(38, 20);
	system("pause");
}


void SetPos(short x, short y)
{
	HANDLE houtput = NULL;
	houtput = GetStdHandle(STD_OUTPUT_HANDLE);

	COORD pos = { x, y };
	SetConsoleCursorPosition(houtput, pos);
}

void WelcomeToGame()
{
	SetPos(38, 12);
	wprintf(L"欢迎来到俄罗斯方块小游戏\n");
	SetPos(38, 20);
	system("pause");
	system("cls");
	SetPos(24, 12);
	wprintf(L"用 ← . → 来控制方块的移动，按空格暂停，按A左转，按D右转，按F3加速，F4减速\n");
	Pause();
	system("cls");
}

void CreateMap()
{
	int i = 0;
	SetPos(0, 0);
	for (i = 0; i <= 11; i++)
	{
		wprintf(L"%lc", WALL);
	}
	SetPos(0, 5);
	for (i = 0; i <= 3; i++)
	{
		wprintf(L"%lc", WALL);
	}
	SetPos(16, 5);
	for (i = 8; i <= 11; i++)
	{
		wprintf(L"%lc", WALL);
	}
	for (i = 0; i <= 26; i++)
	{
		SetPos(0, i);
		wprintf(L"%lc", WALL);
	}
	for (i = 0; i <= 26; i++)
	{
		SetPos(22, i);
		wprintf(L"%lc", WALL);
	}
	SetPos(0, 26);
	for (i = 0; i <= 11; i++)
	{
		wprintf(L"%lc", WALL);
	}
}

void BlockInit(pTetris t)
{
	t->s.type = 0;
	//长条
	t->s.b[0][0].x = 10;
	t->s.b[0][0].y = 1;
	t->s.b[0][1].x = 10;
	t->s.b[0][1].y = 2;
	t->s.b[0][2].x = 10;
	t->s.b[0][2].y = 3;
	t->s.b[0][3].x = 10;
	t->s.b[0][3].y = 4;
	//大方块
	t->s.b[1][0].x = 8;
	t->s.b[1][0].y = 2;
	t->s.b[1][1].x = 10;
	t->s.b[1][1].y = 2;
	t->s.b[1][2].x = 8;
	t->s.b[1][2].y = 3;
	t->s.b[1][3].x = 10;
	t->s.b[1][3].y = 3;
	//左三角
	t->s.b[2][0].x = 8;
	t->s.b[2][0].y = 2;
	t->s.b[2][1].x = 10;
	t->s.b[2][1].y = 2;
	t->s.b[2][2].x = 10;
	t->s.b[2][2].y = 3;
	t->s.b[2][3].x = 10;
	t->s.b[2][3].y = 4;
	//右三角
	t->s.b[3][0].x = 12;
	t->s.b[3][0].y = 2;
	t->s.b[3][1].x = 10;
	t->s.b[3][1].y = 2;
	t->s.b[3][2].x = 10;
	t->s.b[3][2].y = 3;
	t->s.b[3][3].x = 10;
	t->s.b[3][3].y = 4;
	//中三角
	t->s.b[4][0].x = 8;
	t->s.b[4][0].y = 2;
	t->s.b[4][1].x = 10;
	t->s.b[4][1].y = 2;
	t->s.b[4][2].x = 12;
	t->s.b[4][2].y = 3;
	t->s.b[4][3].x = 10;
	t->s.b[4][3].y = 3;
	//左S
	t->s.b[5][0].x = 8;
	t->s.b[5][0].y = 2;
	t->s.b[5][1].x = 10;
	t->s.b[5][1].y = 2;
	t->s.b[5][2].x = 12;
	t->s.b[5][2].y = 3;
	t->s.b[5][3].x = 10;
	t->s.b[5][3].y = 3;
	//右S
	t->s.b[6][0].x = 12;
	t->s.b[6][0].y = 2;
	t->s.b[6][1].x = 10;
	t->s.b[6][1].y = 2;
	t->s.b[6][2].x = 8;
	t->s.b[6][2].y = 3;
	t->s.b[6][3].x = 10;
	t->s.b[6][3].y = 3;
	//这里把每个a[n][2]坐标设为一致，是为了把它当做旋转的中心点，方便后续旋转
	//n==x/2+10*(y-1)-1
}

void BlockTurn(pTetris t)
{
	int n = t->s.type;
	for (int i = 0; i < 4; i++)
	{
		t->s.a[(t->s.b[n][i].x) / 2 + (t->s.b[n][i].y - 1) * 10 - 1].a = 1;
	}
}
void FBlockTurn(pTetris t)
{
	int n = t->s.type;
	for (int i = 0; i < 4; i++)
	{
		t->s.a[(t->s.b[n][i].x) / 2 + (t->s.b[n][i].y - 1) * 10 - 1].a = 0;
	}
}

void TetrisInit(pTetris t)
{	
	BlockInit(t);
	t->_Status = OK;
}

void GameInit(pTetris t)
{
	//1.控制台窗⼝⼤⼩的设置
	system("mode con cols=100 lines=40");


	//2.控制台窗⼝名字的设置
	system("title 俄罗斯方块");


	//3.⿏标光标的隐藏.
	HANDLE houtput = NULL;
	houtput = GetStdHandle(STD_OUTPUT_HANDLE);//获得标准输出设备的句柄

	CONSOLE_CURSOR_INFO cursor_info = { 0 };//定义一个光标信息的结构体

	GetConsoleCursorInfo(houtput, &cursor_info);//获取控制台上的光标信息

	cursor_info.bVisible = false;//设置控制台上的光标的状态为隐藏

	SetConsoleCursorInfo(houtput, &cursor_info);//设置控制台上的光标信息


	
	WelcomeToGame();


	
	CreateMap();


	t->_SleepTime = TIME;
	t->_Socre = 0;
	t->_Row = 0;

}

void OverPrint(pTetris t)
{
	int n = 0;
	for (n = 0; n < 250; n++)
	{
		if (n == 40 || n == 41 || n == 42 || n == 47 || n == 48 || n == 49)
		{
			continue;
		}
		SetPos(t->s.a[n].x, t->s.a[n].y);
		if (t->s.a[n].a == 1)
		{
			wprintf(L"%lc", BLOCK);
		}
		else
		{
			wprintf(" ");
		}
	}
}

void OverInit(pTetris t)
{//2-20,6-15
	int i, j, n = 0;
	for (j = 1; j <= 25; j++)
	{
		for (i = 2; i <= 20; i += 2)
		{
			t->s.a[n].a = 0;
			t->s.a[n].x = i;
			t->s.a[n].y = j;
			n++;
		}
	}
}

void LeftMove(pTetris t)//消除旧的方块，生成新的俄罗斯方块
{
	int n = t->s.type;
	for (int i = 0; i < 4; i++)
	{
		t->s.b[n][i].x -= 2;
	}
}
void RightMove(pTetris t)
{
	int n = t->s.type;
	for (int i = 0; i < 4; i++)
	{
		t->s.b[n][i].x += 2;
	}
}
void DownMove(pTetris t)
{
	int n = t->s.type;
	for (int i = 0; i < 4; i++)
	{
		t->s.b[n][i].y++;
	}
}
void UpMove(pTetris t)
{
	int n = t->s.type;
	for (int i = 0; i < 4; i++)
	{
		t->s.b[n][i].y--;
	}
}
void BlockLeftSpin(pTetris t)
{//x2=2b-2y1+a;y2=b+x1/2-a/2
	int n = t->s.type;
	for (int i = 0; i < 4; i++)
	{
		int x = t->s.b[n][i].x;
		int y = t->s.b[n][i].y;
		if (i == 1)
		{
			continue;
		}//转换成数学问题，勾股定理
		t->s.b[n][i].x = -(2 * t->s.b[n][1].y) + (2 * y) + (t->s.b[n][1].x);
		t->s.b[n][i].y = (t->s.b[n][1].y) + (t->s.b[n][1].x / 2) - (x / 2);
	}
	if (!ax3(t) || !ax4(t))
	{
		BlockRightSpin(t);
	}
}
void BlockRightSpin(pTetris t)
{//x2=2b-2y1+a;y2=b+x1/2-a/2
	int n = t->s.type;
	for (int i = 0; i < 4; i++)
	{
		int x = t->s.b[n][i].x;
		int y = t->s.b[n][i].y;
		if (i == 1)
		{
			continue;
		}
		t->s.b[n][i].x = (2 * t->s.b[n][1].y) - (2 * y) + (t->s.b[n][1].x);
		t->s.b[n][i].y = (t->s.b[n][1].y) - (t->s.b[n][1].x / 2) + (x / 2);
	}
	if (!ax3(t) || !ax4(t))
	{
		BlockLeftSpin(t);
	}
}
bool ax1(pTetris t)//判断右边是否到底，到底返回false
{
	int n = t->s.type;
	for (int i = 0; i < 4; i++)
	{
		if (t->s.b[n][i].x >= 20)
		{
			return false;
		}
	}
	return true;
}
bool ax2(pTetris t)//判断左边是否到底，到底返回false
{
	int n = t->s.type;
	for (int i = 0; i < 4; i++)
	{
		if (t->s.b[n][i].x <= 2)
		{
			return false;
		}
	}
	return true;
}
bool ax3(pTetris t)//判断是否出界,出界返回false
{
	int n = t->s.type;
	for (int i = 0; i < 4; i++)
	{
		if (t->s.b[n][i].y < 6
			|| t->s.b[n][i].y > 25
			|| t->s.b[n][i].x < 2
			|| t->s.b[n][i].x > 20)
		{
			return false;
		}
	}
	return true;
}
bool ax33(pTetris t)
{
	int n = t->s.type;
	for (int i = 0; i < 4; i++)
	{
		if (t->s.b[n][i].y > 25
			|| t->s.b[n][i].x < 2
			|| t->s.b[n][i].x > 20)
		{
			return false;
		}
	}
	return true;
}
bool ax4(pTetris t)//判断是否与块重合，重合返回false
{
	int n = t->s.type;
	for (int i = 0; i < 4; i++)
	{
		if (t->s.a[(t->s.b[n][i].x) / 2 + (t->s.b[n][i].y - 1) * 10 - 1].a == 1)
			return false;
	}
	return true;
}
void BlockMove(pTetris t)
{
	if (KEY_PRESS(VK_RIGHT))
	{
		if (ax1(t) && ax3(t))
		{
			FBlockTurn(t);
			RightMove(t);
			BlockTurn(t);
		}
	}
	else if (KEY_PRESS(VK_LEFT))
	{
		if (ax2(t) && ax3(t))
		{
			FBlockTurn(t);
			LeftMove(t);
			BlockTurn(t);
		}
	}
	else if (KEY_PRESS(65) && ax3(t))
	{
		FBlockTurn(t);
		BlockLeftSpin(t);
		BlockTurn(t);
	}
	else if (KEY_PRESS(68) && ax3(t))
	{
		FBlockTurn(t);
		BlockRightSpin(t);
		BlockTurn(t);
	}

	FBlockTurn(t);
	DownMove(t);


	if (!ax33(t) || !ax4(t))
	{
		UpMove(t);
		BlockTurn(t);
		t->_Operate = RENEW;
	}
}

void AllDownMove(pTetris t)//所有范围内格子下移
{//n == x / 2 + 10 * (y - 1) - 1
	//x:2-20  y:6-25
	int i, j = 0;
	for (i = 2; i <= 20; i += 2)
	{
		for (j = 25; j >= 6; j--)
		{
			t->s.a[(i / 2) + 10 * (j - 1) - 1].a
				= t->s.a[(i / 2) + 10 * ((j - 1) - 1) - 1].a;
		}
	}
}

void BlockClearRow(pTetris t)
{//
	int i, j = 0;
	for (i = 2; i <= 20; i += 2)
	{
		for (j = (t->_Row + 1) / 10; j >= 5; j--)
		{
			t->s.a[(i / 2) + 10 * (j - 1) - 1].a
				= t->s.a[(i / 2) + 10 * ((j - 1) - 1) - 1].a;
		}
	}
	t->_Socre += 1;
}

void BlockClear(pTetris t)
{
	int  i, j = 0;
	for (i = 50; i <= 249; i++)
	{
		if (t->s.a[i].a == 0)
		{
			i = i - (i % 10) + 10;
		}
		if (i % 10 == 9)
		{
			t->_Row = i;//对应行，赋的值为对应行末尾编号
			BlockClearRow(t);
		}
	}
}

void TetrisCheck(pTetris t)
{
	for (int i = 40; i <= 49; i++)
	{
		if (t->s.a[i].a == 1)
		{
			t->_Status = KILL_BY_SELF;
		}
	}
}

void GameRun(pTetris t)
{
	int a;
	OverInit(t);//初始块的状态out(0)
	do
	{
		//打印各种信息
		SetPos(40, 10);
		printf("总分数:%2d\n", t->_Socre);
		SetPos(40, 12);
		printf("用 ← . → 来控制方块的移动\n");
		SetPos(40, 13);
		printf("按空格暂停，按A左转，按D右转，按F3加速，F4减速\n");

		//确认各种状态
		if (KEY_PRESS(VK_SPACE))
		{
			Pause();
		}
		else if (KEY_PRESS(VK_ESCAPE))
		{
			t->_Status = END_NORMAL;
		}
		else if (KEY_PRESS(VK_F3))
		{
			if (t->_SleepTime > 200)
			{
				t->_SleepTime -= 100;
			}
		}
		else if (KEY_PRESS(VK_F4))
		{
			if (t->_SleepTime <= 1000)
			{
				t->_SleepTime += 100;
			}
		}
		else if (KEY_PRESS(VK_ESCAPE))
		{
			t->_Status = END_NORMAL;
		}

		//生成俄罗斯方块
		if (t->_Operate == RENEW)
		{
			TetrisInit(t);
			t->s.type = rand() % 7;
			t->_Operate = NORMAL;
			//检测
			TetrisCheck(t);
		}

		//当一行满的时候,检测并清除
		BlockClear(t);

		
		BlockTurn(t);

		
		OverPrint(t);

	
		BlockMove(t);


		Sleep(t->_SleepTime);
		SetPos(38, 20);
		printf("                    ");
	} while (t->_Status == OK);
}


void GameEnd(pTetris t)
{
	SetPos(38, 20);
	switch (t->_Status)
	{
	case KILL_BY_SELF:
		printf("失败了菜鸡，游戏结束\n");
		break;
	case END_NORMAL:
		printf(" 主动退出 ，游戏结束\n");
		break;
	}
}